//---------------------------------------------------------------------------
#include "vcl_stl.h"
#pragma hdrstop

#include "h_base.h"
#include "h_xml.h"
using namespace h_base;
using namespace h_xml;

#include "h_global.h"
#include "h_g.h"
#include "reinit.hpp"
#include "h_i18n.h"
#include "h_progressbar.h"
#include "t_mainform.h"
#include "h_designcontrol.h"
#include "h_stage.h"
#include "t_aboutform.h"
#include "t_dummyform.h"
#include "t_listform.h"

#include "comobj.hpp"

#include <sys/timeb.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
namespace h_g
{

static list<UTF8String> FRecentJobList;
static map<UTF8String, HStage*> FStageRegister;
static UTF8String WindowStyle;
static UTF8String LogFileName;
static TCriticalSection *DebugCs = NULL;

bool InitFail;
UINT ClipboardFormat;
UTF8String BaseDir;
UTF8String BinDir;
UTF8String RecentOpenDir;
UTF8String FirstJobFileName;
bool Copyright;
bool ExcelFlag;
bool DebugFlag;
vector<string> SpecialDateList;
vector<string> BusinessTypeList;
LCID LocaleID;
UTF8String ClientCodeSet;
const char *JobNameDelimiter = ":";
UTF8String ServerIpAddr;
int ServerPort;
UTF8String ServerProtocol;
Graphics::TBitmap *Background;
Graphics::TBitmap *CustLogo;
Graphics::TBitmap *Logo;
bool CustLogoFlag = true;
bool DirectLink;

TColor IconSelectedColor;
TColor IconRunningColor;
TColor IconSuccessColor;
TColor IconFailedColor;
TColor IconSkippedColor;
TColor IconUnknownColor;
TColor LineColor;
TColor LineShadowColor;
TColor TextColor;
TColor TabTextColor;
vector<TColor> IconTextColors;

Variant ExcelApp;

vector<Graphics::TBitmap*> BitmapArrow;
vector<Graphics::TBitmap*> BitmapConnector;

vector<Graphics::TBitmap*> BitmapBatchBg1;
vector<Graphics::TBitmap*> BitmapBatchBg2;
vector<Graphics::TBitmap*> BitmapBatchBg3;
vector<Graphics::TBitmap*> BitmapJobBg1;
vector<Graphics::TBitmap*> BitmapJobBg2;
vector<Graphics::TBitmap*> BitmapJobBg3;
vector<Graphics::TBitmap*> BitmapExternJobBg1;
vector<Graphics::TBitmap*> BitmapExternJobBg2;
vector<Graphics::TBitmap*> BitmapExternJobBg3;
vector<Graphics::TBitmap*> BitmapGroupBg1;
vector<Graphics::TBitmap*> BitmapGroupBg2;
vector<Graphics::TBitmap*> BitmapGroupBg3;
vector<Graphics::TBitmap*> BitmapExternGroupBg1;
vector<Graphics::TBitmap*> BitmapExternGroupBg2;
vector<Graphics::TBitmap*> BitmapExternGroupBg3;
vector<Graphics::TBitmap*> BitmapFwBg;
vector<Graphics::TBitmap*> BitmapTimeBg;

static int __fastcall ToGray(TColor Color)
{
   unsigned int Red;
   unsigned int Green;
   unsigned int Blue;

   Red = Color & 0x000000ff;
   Green = ( Color & 0x0000ff00 ) >> 8;
   Blue = ( Color & 0x00ff0000 ) >> 16;

   return ( Red * 30 + Green * 59 + Blue * 11 ) / 100 % 256;
}

static unsigned char __fastcall ToGray(const unsigned char SrcBuf[3])
{
   return ( (unsigned int)SrcBuf[2] * 30 + (unsigned int)SrcBuf[1] * 59 +
      (unsigned int)SrcBuf[0] * 11 ) / 100 % 256;
}

static TColor __fastcall CalcColor(TColor Color, int Gray)
{
   unsigned int Red;
   unsigned int Green;
   unsigned int Blue;

   Red = Color & 0x000000ff;
   Green = ( Color & 0x0000ff00 ) >> 8;
   Blue = ( Color & 0x00ff0000 ) >> 16;

   Red = Red * Gray / 256;
   Green = Green * Gray / 256;
   Blue = Blue * Gray / 256;
   return TColor(Red | ( Green << 8 ) | ( Blue << 16 ));
}

static void __fastcall CalcColor(const unsigned char BaseColorBuf[3],
   const unsigned char SrcBuf[3], unsigned char DesBuf[3])
{
   unsigned int Gray = SrcBuf[0];

   DesBuf[2] = BaseColorBuf[2] * Gray / 256;
   DesBuf[1] = BaseColorBuf[1] * Gray / 256;
   DesBuf[0] = BaseColorBuf[0] * Gray / 256;
}

static TColor StrToColor(const char *s)
{
   unsigned int Red;
   unsigned int Green;
   unsigned int Blue;
   int Pos = 0;
   char w[80 + 1];

   Pos += ReadWord(s + Pos, w, ", ", 80);
   Red = StrToInt(w);
   Pos += ReadWord(s + Pos, w, ", ", 80);

   if ( strcmp(w, ",") != 0 )
   {
      return clBlack;
   }

   Pos += ReadWord(s + Pos, w, ", ", 80);
   Green = StrToInt(w);
   Pos += ReadWord(s + Pos, w, ", ", 80);

   if ( strcmp(w, ",") != 0 )
   {
      return clBlack;
   }

   Pos += ReadWord(s + Pos, w, ", ", 80);
   Blue = StrToInt(w);
   return TColor(Red | ( Green << 8 ) | ( Blue << 16 ));
}

static void __fastcall SplitBitmap(const vector<Graphics::TBitmap*> &BitmapVec,
   vector<Graphics::TBitmap*> &BitmapVec1, vector<Graphics::TBitmap*> &BitmapVec2,
   vector<Graphics::TBitmap*> &BitmapVec3)
{
   BitmapVec1.clear();
   BitmapVec2.clear();
   BitmapVec3.clear();

   for ( int i = 0; i < BitmapVec.size(); i++ )
   {
      Graphics::TBitmap *BaseBitmap = BitmapVec[i];
      TColor TransparentColor = BaseBitmap->TransparentColor;
      Graphics::TBitmap *Bitmap1 = new Graphics::TBitmap();
      Bitmap1->PixelFormat = pf24bit;
      Bitmap1->Width = BaseBitmap->Width / 3;
      Bitmap1->Height = BaseBitmap->Height;
      Bitmap1->TransparentMode = tmFixed;
      Bitmap1->TransparentColor = TransparentColor;
      Bitmap1->Transparent = true;
      Graphics::TBitmap *Bitmap2 = new Graphics::TBitmap();
      Bitmap2->PixelFormat = pf24bit;
      Bitmap2->Width = BaseBitmap->Width / 3;
      Bitmap2->Height = BaseBitmap->Height;
      Bitmap2->TransparentMode = tmFixed;
      Bitmap2->TransparentColor = TransparentColor;
      Bitmap2->Transparent = true;
      Graphics::TBitmap *Bitmap3 = new Graphics::TBitmap();
      Bitmap3->PixelFormat = pf24bit;
      Bitmap3->Width = BaseBitmap->Width / 3;
      Bitmap3->Height = BaseBitmap->Height;
      Bitmap3->TransparentMode = tmFixed;
      Bitmap3->TransparentColor = TransparentColor;
      Bitmap3->Transparent = true;
      for ( int y = 0; y < BaseBitmap->Height; y++ )
      {
         unsigned char *BaseBuf = (unsigned char *)BaseBitmap->ScanLine[y];
         unsigned char *Buf1 = (unsigned char *)Bitmap1->ScanLine[y];
         unsigned char *Buf2 = (unsigned char *)Bitmap2->ScanLine[y];
         unsigned char *Buf3 = (unsigned char *)Bitmap3->ScanLine[y];
         for ( int x = 0; x < BaseBitmap->Width / 3; x++ )
         {
            memcpy(Buf1 + x * 3, BaseBuf + x * 3, 3);
            memcpy(Buf2 + x * 3, BaseBuf + ( x + BaseBitmap->Width / 3 ) * 3, 3);
            memcpy(Buf3 + x * 3, BaseBuf + ( x + BaseBitmap->Width / 3 * 2 ) * 3, 3);
         }
      }
      BitmapVec1.push_back(Bitmap1);
      BitmapVec2.push_back(Bitmap2);
      BitmapVec3.push_back(Bitmap3);
   }
}

static void __fastcall FreeBitmaps(vector<Graphics::TBitmap*> &BitmapVec)
{
   for ( int i = 0; i < BitmapVec.size(); i++ )
   {
      delete BitmapVec[i];
   }

   BitmapVec.clear();
}

static void __fastcall LoadArrowBitmap(const UTF8String &Skin)
{
   Graphics::TBitmap *DownArrow = new Graphics::TBitmap();
   UTF8String FileName = BaseDir + "skin\\" + Skin + "\\arrow.bmp";

   if ( !FileExist(FileName) )
   {
      FileName = BaseDir + "skin\\" + "default" + "\\arrow.bmp";
   }

   DownArrow->LoadFromFile(FileName);
   TColor TransparentColor = DownArrow->Canvas->Pixels[0][0];
   DownArrow->TransparentMode = tmFixed;
   DownArrow->TransparentColor = TransparentColor;
   DownArrow->Transparent = true;
   BitmapArrow.push_back(DownArrow);

   Graphics::TBitmap *RightArrow = new Graphics::TBitmap();
   RightArrow->Width = DownArrow->Height;
   RightArrow->Height = DownArrow->Width;
   RightArrow->TransparentMode = tmFixed;
   RightArrow->TransparentColor = TransparentColor;
   RightArrow->Transparent = true;

   for ( int y = 0; y < DownArrow->Height; y++ )
   {
      for ( int x = 0; x < DownArrow->Width; x++ )
      {
         RightArrow->Canvas->Pixels[y][x] = DownArrow->Canvas->Pixels[x][y];
      }
   }

   BitmapArrow.push_back(RightArrow);

   Graphics::TBitmap *UpArrow = new Graphics::TBitmap();
   UpArrow->Width = DownArrow->Width;
   UpArrow->Height = DownArrow->Height;
   UpArrow->TransparentMode = tmFixed;
   UpArrow->TransparentColor = TransparentColor;
   UpArrow->Transparent = true;

   for ( int y = 0; y < DownArrow->Height; y++ )
   {
      for ( int x = 0; x < DownArrow->Width; x++ )
      {
         UpArrow->Canvas->Pixels[x][DownArrow->Height - 1 - y] =
            DownArrow->Canvas->Pixels[x][y];
      }
   }

   BitmapArrow.push_back(UpArrow);

   Graphics::TBitmap *LeftArrow = new Graphics::TBitmap();
   LeftArrow->Width = DownArrow->Height;
   LeftArrow->Height = DownArrow->Width;
   LeftArrow->TransparentMode = tmFixed;
   LeftArrow->TransparentColor = TransparentColor;
   LeftArrow->Transparent = true;

   for ( int y = 0; y < DownArrow->Height; y++ )
   {
      for ( int x = 0; x < DownArrow->Width; x++ )
      {
         LeftArrow->Canvas->Pixels[DownArrow->Height - 1 - y][x] =
            DownArrow->Canvas->Pixels[x][y];
      }
   }

   BitmapArrow.push_back(LeftArrow);
}

static void __fastcall LoadIconBitmap(vector<Graphics::TBitmap*> &BitmapVec,
   const UTF8String &Skin, const UTF8String &IconName)
{
   TColor IconColors[7];

   IconColors[itSelected] = IconSelectedColor;
   IconColors[itRunning] = IconRunningColor;
   IconColors[itSuccess] = IconSuccessColor;
   IconColors[itFailed] = IconFailedColor;
   IconColors[itSkipped] = IconSkippedColor;
   IconColors[itUnknown] = IconUnknownColor;

   Graphics::TBitmap *BaseBitmap = new Graphics::TBitmap();
   UTF8String FileName = BaseDir + "skin\\" + Skin + "\\" + IconName + ".bmp";

   if ( !FileExist(FileName) )
   {
      FileName = BaseDir + "skin\\" + "default" + "\\" + IconName + ".bmp";
   }

   BaseBitmap->PixelFormat = pf24bit;
   BaseBitmap->LoadFromFile(FileName);
   TColor TransparentColor = BaseBitmap->Canvas->Pixels[0][0];
   BaseBitmap->TransparentMode = tmFixed;
   BaseBitmap->TransparentColor = TransparentColor;
   BaseBitmap->Transparent = true;
   BitmapVec.push_back(BaseBitmap);

   unsigned char TransparentColorBuf[3];

   TransparentColorBuf[2] = TransparentColor & 0x000000ff;
   TransparentColorBuf[1] = ( TransparentColor & 0x0000ff00 ) >> 8;
   TransparentColorBuf[0] = ( TransparentColor & 0x00ff0000 ) >> 16;

   Graphics::TBitmap *GrayBitmap = new Graphics::TBitmap();

   GrayBitmap->PixelFormat = pf24bit;
   GrayBitmap->Width = BaseBitmap->Width;
   GrayBitmap->Height = BaseBitmap->Height;

   for ( int y = 0; y < GrayBitmap->Height; y++ )
   {
      unsigned char *BaseBuf = (unsigned char *)BaseBitmap->ScanLine[y];
      unsigned char *Buf = (unsigned char *)GrayBitmap->ScanLine[y];
      for ( int x = 0; x < GrayBitmap->Width; x++, BaseBuf += 3, Buf += 3 )
      {
         if ( memcmp(BaseBuf, TransparentColorBuf, 3) == 0 )
         {
            memcpy(Buf, TransparentColorBuf, 3);
         }
         else
         {
            *Buf = ToGray(BaseBuf);
         }
      }
   }

   for ( int i = 1; i < sizeof(IconColors) / sizeof(TColor); i++ )
   {
      Graphics::TBitmap *Bitmap = new Graphics::TBitmap();
      Bitmap->PixelFormat = pf24bit;
      Bitmap->Width = BaseBitmap->Width;
      Bitmap->Height = BaseBitmap->Height;
      Bitmap->TransparentMode = tmFixed;
      Bitmap->TransparentColor = TransparentColor;
      Bitmap->Transparent = true;
      TColor BaseColor = IconColors[i];
      unsigned char BaseColorBuf[3];
      BaseColorBuf[2] = BaseColor & 0x000000ff;
      BaseColorBuf[1] = ( BaseColor & 0x0000ff00 ) >> 8;
      BaseColorBuf[0] = ( BaseColor & 0x00ff0000 ) >> 16;
      for ( int y = 0; y < GrayBitmap->Height; y++ )
      {
         unsigned char *BaseBuf = (unsigned char *)GrayBitmap->ScanLine[y];
         unsigned char *Buf = (unsigned char *)Bitmap->ScanLine[y];
         for ( int x = 0; x < GrayBitmap->Width; x++, BaseBuf += 3, Buf += 3 )
         {
            if ( memcmp(BaseBuf, TransparentColorBuf, 3) == 0 )
            {
               memcpy(Buf, TransparentColorBuf, 3);
            }
            else
            {
               CalcColor(BaseColorBuf, BaseBuf, Buf);
            }
         }
      }
      BitmapVec.push_back(Bitmap);
   }

   delete GrayBitmap;
}

static bool __fastcall LoadColors(const UTF8String &Skin)
{
   UTF8String FileName = BaseDir + "skin\\" + Skin + "\\colors.xml";

   if ( !FileExist(FileName) )
   {
      FileName = BaseDir + "skin\\" + "default" + "\\colors.xml";
   }

   HXmlTree Colors;

   if ( !Colors.LoadFromFile(FileName.c_str()) )
   {
      UTF8String Err;
      Err.sprintf(h_g::I18nString("h_globalinfo:LOAD_COLORS_FAIL"),
         Colors.GetErrorString().c_str());
      ShowMessage(Err);
      return false;
   }

   IconSelectedColor = StrToColor(
      Colors.GetValue("ICON_SELECTED_COLOR").c_str());
   IconRunningColor = StrToColor(
      Colors.GetValue("ICON_RUNNING_COLOR").c_str());
   IconSuccessColor = StrToColor(
      Colors.GetValue("ICON_SUCCESS_COLOR").c_str());
   IconFailedColor = StrToColor(
      Colors.GetValue("ICON_FAILED_COLOR").c_str());
   IconSkippedColor = StrToColor(
      Colors.GetValue("ICON_SKIPPED_COLOR").c_str());
   IconUnknownColor = StrToColor(
      Colors.GetValue("ICON_UNKNOWN_COLOR").c_str());
   LineColor = StrToColor(
      Colors.GetValue("LINE_COLOR").c_str());
   LineShadowColor = StrToColor(
      Colors.GetValue("LINE_SHADOW_COLOR").c_str());
   TextColor = StrToColor(
      Colors.GetValue("TEXT_COLOR").c_str());
   TabTextColor = StrToColor(
      Colors.GetValue("TAB_TEXT_COLOR").c_str());

   IconTextColors.clear();

   for ( int i = 0; i < 7; i++ )
   {
      IconTextColors.push_back(clBlack);
   }

   IconTextColors[itNormal] = StrToColor(
      Colors.GetValue("ICON_NORMAL_TEXT_COLOR").c_str());
   IconTextColors[itSelected] = StrToColor(
      Colors.GetValue("ICON_SELECTED_TEXT_COLOR").c_str());
   IconTextColors[itRunning] = StrToColor(
      Colors.GetValue("ICON_RUNNING_TEXT_COLOR").c_str());
   IconTextColors[itSuccess] = StrToColor(
      Colors.GetValue("ICON_SUCCESS_TEXT_COLOR").c_str());
   IconTextColors[itFailed] = StrToColor(
      Colors.GetValue("ICON_FAILED_TEXT_COLOR").c_str());
   IconTextColors[itSkipped] = StrToColor(
      Colors.GetValue("ICON_SKIPPED_TEXT_COLOR").c_str());
   IconTextColors[itUnknown] = StrToColor(
      Colors.GetValue("ICON_UNKNOWN_TEXT_COLOR").c_str());

   CustLogoFlag = ( Colors.GetValueUpper("CUST_LOGO") != "FALSE" );
   WindowStyle = Colors.GetValue("WINDOW_STYLE", "Windows").c_str();
   return true;
}

static void LoadButtonIcon(const UTF8String &Skin,
   int Index, const UTF8String &Name)
{
   Graphics::TBitmap *ButtonBitmap = new Graphics::TBitmap();
   Graphics::TBitmap *MaskBitmap = new Graphics::TBitmap();
   UTF8String FileName = BaseDir + "skin\\" + Skin + "\\button_" + Name + ".bmp";

   if ( !FileExist(FileName) )
   {
      FileName = BaseDir + "skin\\" + "default" + "\\button_" + Name + ".bmp";
   }

   ButtonBitmap->LoadFromFile(FileName);
   MaskBitmap->Assign(ButtonBitmap);
   MaskBitmap->Mask(ButtonBitmap->Canvas->Pixels[0][0]);
   MainForm->ImageList1->Replace(Index, ButtonBitmap, MaskBitmap);
   delete ButtonBitmap;
   delete MaskBitmap;
}

static void __fastcall LoadSkin(const UTF8String &Skin)
{
   Background = new Graphics::TBitmap();

   UTF8String FileName;

   FileName = BaseDir + "skin\\" + Skin + "\\background.bmp";

   if ( !FileExist(FileName) )
   {
      FileName = BaseDir + "skin\\" + "default" + "\\background.bmp";
   }

   Background->LoadFromFile(FileName);

   LoadColors(Skin);

   if ( CustLogoFlag )
   {
      FileName = BaseDir + "skin\\" + Skin + "\\cust_logo.bmp";
      if ( !FileExist(FileName) )
      {
         FileName = BaseDir + "skin\\" + "default" + "\\cust_logo.bmp";
      }
      if ( FileExist(FileName) )
      {
         CustLogo = new Graphics::TBitmap();
         CustLogo->LoadFromFile(FileName);
         TColor TransparentColor = CustLogo->Canvas->Pixels[0][0];
         CustLogo->TransparentMode = tmFixed;
         CustLogo->TransparentColor = TransparentColor;
         CustLogo->Transparent = true;
      }
   }

   LoadIconBitmap(BitmapConnector, Skin, "connector");
   LoadArrowBitmap(Skin);

   LoadIconBitmap(BitmapFwBg, Skin, "fw_bg");
   LoadIconBitmap(BitmapTimeBg, Skin, "time_bg");

   {
      vector<Graphics::TBitmap*> BitmapExternJobBg;
      LoadIconBitmap(BitmapExternJobBg, Skin, "extern_job_bg");
      SplitBitmap(BitmapExternJobBg, BitmapExternJobBg1, BitmapExternJobBg2, BitmapExternJobBg3);
      FreeBitmaps(BitmapExternJobBg);
   }

   {
      vector<Graphics::TBitmap*> BitmapGroupBg;
      LoadIconBitmap(BitmapGroupBg, Skin, "group_bg");
      SplitBitmap(BitmapGroupBg, BitmapGroupBg1, BitmapGroupBg2, BitmapGroupBg3);
      FreeBitmaps(BitmapGroupBg);
   }

   {
      vector<Graphics::TBitmap*> BitmapJobBg;
      LoadIconBitmap(BitmapJobBg, Skin, "job_bg");
      SplitBitmap(BitmapJobBg, BitmapJobBg1, BitmapJobBg2, BitmapJobBg3);
      FreeBitmaps(BitmapJobBg);
   }

   {
      vector<Graphics::TBitmap*> BitmapBatchBg;
      LoadIconBitmap(BitmapBatchBg, Skin, "batch_bg");
      SplitBitmap(BitmapBatchBg, BitmapBatchBg1, BitmapBatchBg2, BitmapBatchBg3);
      FreeBitmaps(BitmapBatchBg);
   }

   LoadButtonIcon(Skin, 0, "new");
   LoadButtonIcon(Skin, 1, "open");
   LoadButtonIcon(Skin, 2, "save");
   LoadButtonIcon(Skin, 3, "undo");
   LoadButtonIcon(Skin, 4, "redo");
   LoadButtonIcon(Skin, 5, "transfer");
   LoadButtonIcon(Skin, 6, "arrow");
   LoadButtonIcon(Skin, 7, "link");
   LoadButtonIcon(Skin, 8, "delete");
   LoadButtonIcon(Skin, 9, "job");
   LoadButtonIcon(Skin, 10, "connector");
   LoadButtonIcon(Skin, 11, "extern_job");
   LoadButtonIcon(Skin, 12, "event_fire");
   LoadButtonIcon(Skin, 13, "event_wait");
   LoadButtonIcon(Skin, 14, "group");
   LoadButtonIcon(Skin, 15, "home");
   LoadButtonIcon(Skin, 16, "cut");
   LoadButtonIcon(Skin, 17, "copy");
   LoadButtonIcon(Skin, 18, "paste");
   LoadButtonIcon(Skin, 19, "list");
   LoadButtonIcon(Skin, 20, "up");
   LoadButtonIcon(Skin, 21, "time");
   LoadButtonIcon(Skin, 22, "batch");
   LoadButtonIcon(Skin, 21, "time");

   TStyleManager::TrySetStyle(WindowStyle);
   MainForm->Invalidate();
   MainForm->RefreshCaption();
   MainForm->CurrentDesignControl()->Invalidate();
}

static void __fastcall FreeSkin()
{
   delete Background;

   if ( CustLogo != NULL )
   {
      delete CustLogo;
      CustLogo = NULL;
   }

   FreeBitmaps(BitmapConnector);
   FreeBitmaps(BitmapArrow);
   FreeBitmaps(BitmapFwBg);
   FreeBitmaps(BitmapTimeBg);
   FreeBitmaps(BitmapExternJobBg1);
   FreeBitmaps(BitmapExternJobBg2);
   FreeBitmaps(BitmapExternJobBg3);
   FreeBitmaps(BitmapGroupBg1);
   FreeBitmaps(BitmapGroupBg2);
   FreeBitmaps(BitmapGroupBg3);
   FreeBitmaps(BitmapJobBg1);
   FreeBitmaps(BitmapJobBg2);
   FreeBitmaps(BitmapJobBg3);
}

void __fastcall Init()
{
   InitFail = false;
   HComm::Init();
   DebugFlag = false;
   DebugCs = new TCriticalSection();
   LogFileName = "debug.log";
   ClipboardFormat = RegisterClipboardFormatW(L"SIMJIE_SBT");
   BinDir = ExtractFilePath(Application->ExeName);

   {
	  UTF8String TmpStr = ExtractFilePath(ExcludeTrailingBackslash(BinDir));
	  if ( TmpStr == "" )
	  {
		 BaseDir = BinDir;
	  }
	  else
	  {
		 BaseDir = TmpStr;
	  }
   }

   ForceDirectories(BaseDir + "bats");
   RecentOpenDir = BaseDir + "bats";

   if ( ParamCount() == 0 )
   {
      FirstJobFileName = "";
   }
   else
   {
      FirstJobFileName = ParamStr(1);
   }

   RegisterStage("JOB", new HStageJob);
   RegisterStage("CONNECTOR", new HStageConnector);
   RegisterStage("EXTERN_JOB", new HStageExternJob);
   RegisterStage("EVENT_FIRE", new HStageEventFire);
   RegisterStage("EVENT_WAIT", new HStageEventWait);
   RegisterStage("GROUP", new HStageGroup);
   RegisterStage("TIME", new HStageTime);
   RegisterStage("BATCH", new HStageBatch);

   HXmlTree Config;

   if ( !Config.LoadFromFile((BinDir + "simbat.cfg").c_str()) )
   {
      char Err[200 + 1];
      snprintf(Err, 200, "Load simbat.cfg fail, %s", Config.GetErrorString().c_str());
      ShowMessage(UTF8String(Err));
      InitFail = true;
   }

   HXmlTree *Cfg;

   UTF8String Skin;
   UTF8String Locale;

   Cfg = Config.ForceGetChild("COMMON");
   Skin = Cfg->GetValue("SKIN", "DEFAULT").c_str();
   Locale = Cfg->GetValue("LOCALE", "").c_str();
   Copyright = Cfg->GetValueUpper("COPYRIGHT", "") != "FALSE";

#ifdef SIMBAT_ENTERPRISE
   ExcelFlag = Cfg->GetValueUpper("EXCEL", "") == "TRUE";
#endif

   DebugFlag = Cfg->GetValueUpper("DEBUG") == "TRUE";

   Cfg = Config.ForceGetChild("DESIGNER");
   Cfg->GetValues("SPECIAL_DATE_LIST", SpecialDateList);
   Cfg->GetValues("BUSINESS_TYPE_LIST", BusinessTypeList);

   {
      vector<string> StrVec;
      Cfg->GetValues("RECENT_JOB_LIST", StrVec);
      for ( int i = 0; i < StrVec.size(); i++ )
      {
         FRecentJobList.push_back(StrVec[i].c_str());
      }
   }

   MainForm->RefreshRecentJobList(FRecentJobList);

   int I18nIdx = 0;

   if ( Locale == "CHS" )
   {
      LocaleID = ( SUBLANG_CHINESE_SIMPLIFIED << 10 ) | LANG_CHINESE;
      I18nIdx = 2;
   }
   else if ( Locale == "ZHH" )
   {
      LocaleID = ( SUBLANG_CHINESE_HONGKONG << 10 ) | LANG_CHINESE;
      I18nIdx = 3;
   }
   else if ( Locale == "ENU" )
   {
      LocaleID = ( SUBLANG_ENGLISH_US << 10 ) | LANG_ENGLISH;
      I18nIdx = 1;
   }
   else
   {
      LocaleID = GetSystemDefaultLCID();
      if ( LocaleID == ( ( SUBLANG_CHINESE_SIMPLIFIED << 10 ) | LANG_CHINESE ) )
      {
         I18nIdx = 2;
      }
      else if ( LocaleID == ( ( SUBLANG_CHINESE_HONGKONG << 10 ) | LANG_CHINESE ) )
      {
         I18nIdx = 3;
      }
      else
      {
         I18nIdx = 1;
      }
   }

   I18nInit(I18nIdx);
   ClientCodeSet = "UTF8";

   if ( LoadNewResourceModule(LocaleID) )
   {
      ReinitializeForms();
   }

   MainForm->NewGroup();
   LoadSkin(Skin);

   if ( Copyright )
   {
      Logo = DummyForm->ImageToolbarLogo->Picture->Bitmap;
   }
   else
   {
      Logo = new Graphics::TBitmap();
      UTF8String FileName;
      FileName = BinDir + "logo.bmp";
      Logo->LoadFromFile(FileName);
      AboutForm->Label2->Caption = "";
      AboutForm->Label3->Caption = "";
      AboutForm->Label5->Caption = "";
   }

   ListForm->Clear();
   MainForm->ProgressBar = new HProgressBar(MainForm);
   MainForm->ProgressBar->Width = 150;
   MainForm->ProgressBar->Left = 850;
   MainForm->ProgressBar->Rate = 30;
   MainForm->ProgressBar->ShowFlag = false;
   MainForm->ProgressBar->Parent = MainForm->ToolBarMain;

#ifdef SIMBAT_ENTERPRISE
   AboutForm->LabelEdition->Caption = UTF8String(I18nString("h_g:ENTERPRISE_EDITION"));
#else
   AboutForm->LabelEdition->Caption = UTF8String(I18nString("h_g:COMMUNITY_EDITION"));
#endif

   if ( ExcelFlag )
   {
      try
      {
         ExcelApp = CreateOleObject ("Excel.Application");
		   ExcelApp.OlePropertySet("DisplayAlerts", (Variant)false);
//         ExcelApp.OlePropertySet("Visible", (Variant)true);
      }
      catch(...)
      {
         ShowMessage("Init EXCEL fail");
         ExcelFlag = false;
      }
   }
}

void __fastcall Close()
{
   for ( map<UTF8String, HStage *>::iterator Iter = FStageRegister.begin();
        Iter != FStageRegister.end(); ++Iter )
   {
      delete Iter->second;
   }

   if ( InitFail )
   {
      return;
   }

   if ( ExcelFlag )
   {
	 try
	  {
		 ExcelApp.OleFunction("Quit");
		 ExcelApp = Unassigned();
	  }
	  catch(...)
	  {
		 ShowMessage("Quit Excel fail");
	  }
	  ExcelFlag = false;
   }

   HXmlTree Config;
   UTF8String FileName = BinDir + "simbat.cfg";

   if ( Config.LoadFromFile(FileName.c_str()) )
   {
      HXmlTree *Cfg = Config.ForceGetChild("DESIGNER");
      vector<string> StrVec;
      for ( list<UTF8String>::iterator Iter = FRecentJobList.begin();
           Iter != FRecentJobList.end(); Iter++ )
      {
         StrVec.push_back(Iter->c_str());
      }
      Cfg->SetValues("RECENT_JOB_LIST", StrVec);
      Config.SaveToFile(FileName.c_str());
   }

   FreeSkin();
}

void __fastcall RegisterStage(const UTF8String &Type, HStage *Prototype)
{
   FStageRegister[Type] = Prototype;
}

HStage * __fastcall CloneStage(const UTF8String &Type)
{
   return FStageRegister[Type]->Clone();
}

void __fastcall AddRecentJobPath(const UTF8String &Path)
{
   if ( !FRecentJobList.empty() && FRecentJobList.front() == Path )
   {
      return;
   }

   list<UTF8String>::iterator Iter = find(FRecentJobList.begin(),
      FRecentJobList.end(), Path);

   if ( Iter != FRecentJobList.end() )
   {
      FRecentJobList.erase(Iter);
   }

   if ( FRecentJobList.size() == 10 )
   {
      FRecentJobList.erase(--FRecentJobList.end());
   }

   FRecentJobList.push_front(Path);
   MainForm->RefreshRecentJobList(FRecentJobList);
}

bool __fastcall LoadSbt(HXmlTree &Xml, const UTF8String &FileName,
   UTF8String &ErrStr, bool &ChangeFlag, bool &XmlPropertyFlag)
{
   XmlPropertyFlag = false;

   if ( !Xml.LoadFromFile(FileName.c_str()) )
   {
      ErrStr = UTF8String(Xml.GetErrorString().c_str());
      return false;
   }

   ChangeFlag = false;
   vector<string> Version;
   SplitString(Xml.GetValue("VERSION"), '.', Version);

   if ( Version.size() != 3 )
   {
      ErrStr = UTF8String(h_g::I18nString("h_globalinfo:INVALID_VERSION"));
      return false;
   }

   int Ver = StrToInt(Version[0].c_str()) * 256 + StrToInt(Version[1].c_str());

   if ( Ver <= 0 || Ver > VER_THIS )
   {
      ErrStr = UTF8String(h_g::I18nString("h_globalinfo:INVALID_VERSION"));
      return false;
   }

   if ( Ver != VER_THIS )
   {
      ChangeFlag = true;
   }

   XmlPropertyFlag = ( Ver >= 0x0204 );

   if ( Ver <= 0x0101 )
   {
      vector<HXmlTree*> Groups;
      Xml.GetChildren("GROUP", Groups);
      for ( int i = 0; i < Groups.size(); i++ )
      {
         vector<HXmlTree*> Jobs;
         Groups[i]->GetChildren("JOB", Jobs);
         for ( int j = 0; j < Jobs.size(); j++ )
         {
            if ( Jobs[j]->GetValueUpper("TYPE") != "JOB" )
            {
               continue;
            }
            Jobs[j]->SetValues("DESCRIPTION", Jobs[j]->GetValue("DESCRIPTION"));
         }
      }
      Xml.SetValues("DESCRIPTION", Xml.GetValue("DESCRIPTION"));
      return true;
   }


   if ( Ver < 0x0104 )
   {
      Xml.SetValues("DESCRIPTION", Xml.GetValue("DESCRIPTION"));
      return true;
   }

   return true;
}

void __fastcall ChangeSkin(const UTF8String &Skin)
{
   FreeSkin();
   LoadSkin(Skin);
   HXmlTree Config;
   UTF8String FileName = BinDir + "simbat.cfg";

   Config.LoadFromFile(FileName.c_str());
   HXmlTree *Cfg = Config.ForceGetChild("COMMON");
   Cfg->SetValue("SKIN", Skin.c_str());
   Config.SaveToFile(FileName.c_str());
}

void WriteLog(const char *FormatStr, ...)
{
   DebugCs->Enter();

   if ( !DebugFlag )
   {
      DebugCs->Leave();
      return;
   }

   va_list      VaList;
   FILE         *f;
   struct timeb Time;
   time_t t;
   struct tm    *tm;

   f = _wfopen(UnicodeString(LogFileName).c_str(), L"at");

   if ( f == NULL )
   {
      DebugCs->Leave();
      return;
   }

   ftime(&Time);
   t = Time.time;
   tm = localtime(&t);
   fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%03d  ",
      1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
      tm->tm_hour, tm->tm_min, tm->tm_sec, Time.millitm);
   va_start(VaList, FormatStr);
   vfprintf(f, FormatStr, VaList);
   va_end(VaList);
   fprintf(f, "\n");
   fclose(f);
   DebugCs->Leave();
}

};
